package net.jingkao.app.common;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Map;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.httpclient.params.HttpMethodParams;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;


/**
 * 客户端，用于发送HTTP请求访问网络数据
 * @author chao
 *
 */
public class WebClient {
	
	private final static String TAG = "WebClient";
	
	private final static int TIMEOUT_CONNECTION = 20000;
	private final static int TIMEOUT_SOCKET = 20000;
	private final static int RETRY_TIME = 3;
	private final static long RETRY_INTERVAL = 500;

	private static String appUserAgent;
	
	private static String getUserAgent(){
		if(!StringUtils.isEmpty(appUserAgent)){
			return appUserAgent;
		}
		StringBuilder ua = new StringBuilder("jingkao.net");
		ua.append("/Android");//手机系统平台
		ua.append("/"+android.os.Build.VERSION.RELEASE);//手机系统版本
		ua.append("/"+android.os.Build.MODEL); //手机型号
		appUserAgent = ua.toString();
		return appUserAgent; 
	}
	
	
	
	private static HttpClient getHttpClient() {
        HttpClient httpClient = new HttpClient();
		// 设置 HttpClient不接收 Cookie
		httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        // 设置 默认的超时重试处理策略
		httpClient.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
		// 设置 连接超时时间
		httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(TIMEOUT_CONNECTION);
		// 设置 读数据超时时间 
		httpClient.getHttpConnectionManager().getParams().setSoTimeout(TIMEOUT_SOCKET);
		// 设置 字符集
		httpClient.getParams().setContentCharset("UTF-8");
		return httpClient;
	}
	
	private static GetMethod getHttpGet(String url) {
		GetMethod httpGet = new GetMethod(url);
		// 设置 请求超时时间
		httpGet.getParams().setSoTimeout(TIMEOUT_SOCKET);
		httpGet.setRequestHeader("Host", URLs.HOST);
		httpGet.setRequestHeader("Connection","Keep-Alive");
		httpGet.setRequestHeader("User-Agent", getUserAgent());
		return httpGet;
	}
	
	
	private static PostMethod getHttpPost(String url) {
		PostMethod httpPost = new PostMethod(url);
		// 设置 请求超时时间
		httpPost.getParams().setSoTimeout(TIMEOUT_SOCKET);
		httpPost.setRequestHeader("Host", URLs.HOST);
		httpPost.setRequestHeader("Connection","Keep-Alive");
		httpPost.setRequestHeader("User-Agent", getUserAgent());
		return httpPost;
	}
	
	private static String makeURL(String p_url, Map<String, Object> params) {
		StringBuilder url = new StringBuilder(p_url);
		if(url.indexOf("?")<0)
			url.append('?');

		for(String name : params.keySet()){
			url.append('&');
			url.append(name);
			url.append('=');
			try {
				//URLEncoder处理
				url.append(URLEncoder.encode(String.valueOf(params.get(name)), "UTF-8"));
			} catch (UnsupportedEncodingException e) {
				//理论上不应该发生
				url.append(String.valueOf(params.get(name)));
			}
		}

		return url.toString().replace("?&", "?");
	}
	
	
	/**
	 * get请求URL
	 * @param url
	 * @throws AppException 
	 */
	public static byte[] httpGet(String url, Map<String, Object> params) throws AppException {
		HttpClient httpClient = null;
		GetMethod httpGet = null;

		byte[] responseData = null;
		
		int time = 0;
		do{
			try 
			{
				httpClient = getHttpClient();
				httpGet = getHttpGet(makeURL(url, params));			
				int statusCode = httpClient.executeMethod(httpGet);
				Logger.getLog(WebClient.class).d("URL:%s, StatusCode: %d", makeURL(url, params), statusCode);
				if (statusCode != HttpStatus.SC_OK) {
					throw AppException.http(statusCode);
				}
				ByteArrayOutputStream out = new ByteArrayOutputStream();
				InputStream in = httpGet.getResponseBodyAsStream();
				int reads = in.read();
				while(reads != -1){
					out.write(reads);
					reads = in.read();
				}
				responseData = out.toByteArray();
				out.close();
				break;
			} catch (HttpException e) {
				time++;
				if(time < RETRY_TIME) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e1) {} 
					continue;
				}
				// 发生致命的异常，可能是协议不对或者返回的内容有问题
				e.printStackTrace();
				throw AppException.error(e);
			} catch (IOException e) {
				time++;
				if(time < RETRY_TIME) {
					ThreadUtils.sleep(RETRY_INTERVAL);
					continue;
				}
				// 发生网络异常
				e.printStackTrace();
				throw AppException.error(e);
			} finally {
				// 释放连接
				httpGet.releaseConnection();
				httpClient = null;
			}
		}while(time < RETRY_TIME);
		
		return responseData;
	}
	
	/**
	 * 公用post方法
	 * @param url
	 * @param params
	 * @param files
	 * @throws AppException
	 */
	public static byte[] httpPost(String url, Map<String, Object> params, Map<String,File> files) throws AppException {
		
		HttpClient httpClient = null;
		PostMethod httpPost = null;
		byte[] responseData = null;
		
		//post表单参数处理
		int length = (params == null ? 0 : params.size()) + (files == null ? 0 : files.size());
		Part[] parts = new Part[length];
		int i = 0;
        if(params != null)
        for(String name : params.keySet()){
        	parts[i++] = new StringPart(name, String.valueOf(params.get(name)), "UTF-8");
        	//System.out.println("post_key==> "+name+"    value==>"+String.valueOf(params.get(name)));
        }
        if(files != null)
        for(String file : files.keySet()){
        	try {
				parts[i++] = new FilePart(file, files.get(file));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
        }
		
		int time = 0;
		do{
			try 
			{
				httpClient = getHttpClient();
				httpPost = getHttpPost(url);	        
		        httpPost.setRequestEntity(new MultipartRequestEntity(parts,httpPost.getParams()));		        
		        int statusCode = httpClient.executeMethod(httpPost);
		        if(statusCode != HttpStatus.SC_OK){
		        	throw AppException.http(statusCode);
		        }
		        ByteArrayOutputStream out = new ByteArrayOutputStream();
				InputStream in = httpPost.getResponseBodyAsStream();
				int reads = in.read();
				while(reads != -1){
					out.write(reads);
					reads = in.read();
				}
				responseData = out.toByteArray();
				out.close();
		     	break;	 
		     	    	
			} catch (HttpException e) {
				time++;
				if(time < RETRY_TIME) {
					ThreadUtils.sleep(RETRY_INTERVAL);
					continue;
				}
				// 发生致命的异常，可能是协议不对或者返回的内容有问题
				e.printStackTrace();
				throw AppException.error(e);
			} catch (IOException e) {
				time++;
				if(time < RETRY_TIME) {
					ThreadUtils.sleep(RETRY_INTERVAL);
					continue;
				}
				// 发生网络异常
				e.printStackTrace();
				throw AppException.error(e);
			} finally {
				// 释放连接
				httpPost.releaseConnection();
				httpClient = null;
			}
		}while(time < RETRY_TIME);
        
        return responseData;
	}
	
	/**
	 * 检查参数是否为null，如果为null则返回空的map
	 * @param params
	 * @return
	 */
	static <K, T> Map<K, T> checkParams(Map<K, T> params){
		if(params == null){
			return Collections.emptyMap();
		}else{
			return params;
		}
	}
	
	public static HttpResponse get(String url, Map<String, Object> params){
		params = checkParams(params);
		byte[] data = httpGet(url, params);
		return new HttpResponse(data);
	}
	
	public static HttpResponse post(String url, Map<String, Object> params, Map<String,File> files){
		params = checkParams(params);
		files = checkParams(files);
		byte[] data = httpPost(url, params, files);
		return new HttpResponse(data);
	}
	
	/**
	 * 获取网络图片
	 * @param url
	 * @return
	 */
	public static Bitmap getNetBitmap(String url, Map<String, Object> params) throws AppException {
		params = checkParams(params);
		byte[] data = httpGet(url, params);
		Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
		return bitmap;
	}
	
}
